package org.rcgwt.client.ui.validator.impl;

import java.util.Map;

import org.rcgwt.client.ui.validator.IChecker;
import org.rcgwt.client.ui.validator.IClientValidatorContext;
import org.rcgwt.client.ui.validator.messages.Severity;
import org.rcgwt.client.util.Pattern;
import org.rcgwt.client.util.PatternBuilder;

/**
 * A Checker which checks numbers with parameters(signed ?, decimal-sign,
 * Negative-Signs, ...)
 * 
 * @author Elian ORIOU
 * 
 */

public class NumberChecker implements IChecker {

	private static boolean isSigned = false;
	private static boolean isMinBorned = false;
	private static boolean isMaxBorned = false;
	private static boolean isBothBorned = false;

	private static String decSign = ".";
	private static String negSign = "-";

	private static int min = 0;
	private static int max = 0;

	private Pattern SIGNED_NUMBER_PATTERN;
	private Pattern NUMBER_PATTERN;

	public NumberChecker(Map<String, String> parameters) {

		/* Parameters */
		if (parameters.containsKey("number.signed")) {
			isSigned = Boolean.parseBoolean(parameters.get("number.signed"));
		}
		if (parameters.containsKey("number.decSign")) {
			decSign = parameters.get("number.decSign");
		}
		if (isSigned && parameters.containsKey("number.negSign")) {
			negSign = parameters.get("number.negSign");
		}
		if (parameters.containsKey("number.min")) {
			isMinBorned = true;
			min = Integer.parseInt(parameters.get("number.min"));
		}
		if (parameters.containsKey("number.max")) {
			isMaxBorned = true;
			max = Integer.parseInt(parameters.get("number.max"));
		}
		if (isMinBorned == true && isMaxBorned == true) {
			isBothBorned = true;
		}

		/* Patterns */

		SIGNED_NUMBER_PATTERN = Pattern.compile(PatternBuilder.encode(
				"^[%%1]?[0-9]+([%%2])?[0-9]*$", negSign, decSign));
		NUMBER_PATTERN = Pattern.compile(PatternBuilder.encode(
				"^[0-9]+([%%1])?[0-9]*$", decSign));
	}

	@Override
	public boolean check(IClientValidatorContext context, String s) {

		if (isSigned && SIGNED_NUMBER_PATTERN.matches(s)) {
			int number = Integer.parseInt(s.substring(1));
			if (isBothBorned == true) {
				if (number >= min && number <= max) {
					return true;
				} else {
					launchInvalidNumberMinError(context, min);
					return false;
				}
			}
			if (isMinBorned == true) {
				if (number >= min) {
					return true;
				} else {
					launchInvalidNumberMinError(context, min);
					return false;
				}
			}
			if (isMaxBorned == true) {
				if (number <= max) {
					return true;
				} else {
					launchInvalidNumberMaxError(context, max);
					return false;
				}
			}
			if (isMaxBorned == false && isMinBorned == false
					&& isBothBorned == false) {
				return true;
			}
			launchStructureError(context);
			return false;
		} else if (!isSigned && NUMBER_PATTERN.matches(s)) {
			int number = Integer.parseInt(s);
			if (isBothBorned == true) {
				if (number >= min && number <= max) {
					return true;
				} else {
					launchInvalidNumberRangeError(context, min, max);
					return false;
				}
			}
			if (isMinBorned == true) {
				if (number >= min) {
					return true;
				} else {
					launchInvalidNumberMinError(context, min);
					return false;
				}
			}
			if (isMaxBorned == true) {
				if (number <= max) {
					return true;
				} else {
					launchInvalidNumberMaxError(context, max);
					return false;
				}
			}
			if (isMaxBorned == false && isMinBorned == false
					&& isBothBorned == false) {
				return true;
			}
			launchStructureError(context);
			return false;
		} else {
			launchStructureError(context);
			return false;
		}
	}

	private void launchStructureError(IClientValidatorContext context) {
		context.addMessage(context.getMessagesProvider().StructureErrorShort(),
				context.getMessagesProvider().StructureError(), Severity.ERROR);
	}

	private void launchInvalidNumberMinError(IClientValidatorContext context,
			int min) {
		context.addMessage(context.getMessagesProvider()
				.InvalidNumberMinErrorShort(min), context.getMessagesProvider()
				.InvalidNumberMinError(min), Severity.ERROR);
	}

	private void launchInvalidNumberMaxError(IClientValidatorContext context,
			int max) {
		context.addMessage(context.getMessagesProvider()
				.InvalidNumberMaxErrorShort(max), context.getMessagesProvider()
				.InvalidNumberMaxError(max), Severity.ERROR);
	}

	private void launchInvalidNumberRangeError(IClientValidatorContext context,
			int min, int max) {
		context.addMessage(context.getMessagesProvider()
				.InvalidNumberRangeErrorShort(min, max), context
				.getMessagesProvider().InvalidNumberRangeError(min, max),
				Severity.ERROR);
	}
}
